/* =========================================================================
 *
 *   The traffic processor.
 *
 *   Development by Sedelnikov Alexander (Bigking).
 *
 * =========================================================================
 */

#include "common.h"
#include "thread.h"

//-----------------------------------------------------------------------//
bool  file_exist( const char *fname )
{
    FILE *fp = fopen( fname, "rb" );

    if( fp != NULL )
    {
        fclose( fp );
        return true;
    }

    return false;
}


//-----------------------------------------------------------------------//
ulong file_size ( const char *fname )
{
    ulong fsize = 0;

    FILE *fp = fopen( fname, "rb" );
    fseek( fp, 0, 2 );
    fsize = ftell( fp );
    fclose( fp );

    return fsize;
}


//-----------------------------------------------------------------------//
bool file_extension_check( const char *fname, const char *mask )
{
    const int   mask_len  = strlen( mask );
          int   fn_len    = strlen( fname );

    if( mask_len > fn_len )
        return false;

    fn_len -= mask_len;

    for( int i = 0; i < mask_len; i++ )
        if( mask[ i ] != fname[ i + fn_len ] )
            return false;

    return true;
}


//-------------------------------------------------------------------------//
char *file_basename( const char *fname, char *out, int max_len )
{
    int fn_len = strlen( fname ),
        begin  = -1,
        end    = -1,
        i      = 0;

    out[ 0 ]   = 0;

    for( i = fn_len - 1; i > 0; i-- )
    {
        if( fname[ i ] == '/'
#ifdef _WIN32
            || fname[ i ] == '\\'
#endif
          )
        {
            begin = i + 1;
            break;
        }

        if( fname[ i ] == '.' && end < 0 )
            end = i;
    }

    if( end < 0 )
        end = fn_len;

    if( begin < 0 )
        begin = 0;

    for( i = begin; i < end && i - begin < max_len; i++ )
        out[ i - begin ] = fname[ i ];

    out[ i - begin ] = 0;

    return out;
}


//-------------------------------------------------------------------------//
char *file_extension( const char *fname, char *out, int max_len )
{
    int fn_len = strlen( fname ), begin = -1, i;

    out[ 0 ]   = 0;

    for( i = fn_len - 1; i > 0; i-- )
    {
        if( fname[ i ] == '/'
#ifdef _WIN32
            || fname[ i ] == '\\'
#endif
          )
            break;

        if( fname[ i ] == '.' )
        {
            begin = i + 1;
            break;
        }

    }

    if( begin < 0 )
        return out;

    for( i = begin; i < fn_len && i - begin < max_len; i++ )
        out[ i - begin ] = fname[ i ];

    out[ fn_len - begin ] = 0;

    puts( out );
    puts( out );
    puts( out );

    return out;
}


//-------------------------------------------------------------------------//
char *file_path( const char *fname, char *out, int max_len )
{
    int fn_len = strlen( fname ), end = -1, i;

    out[ 0 ]   = 0;

    if( fn_len > max_len )
        fn_len = max_len; // @fixme May be error.

    for( i = fn_len - 1; i >= 0; i-- )
    {
        if( fname[ i ] == '/'
#ifdef _WIN32
            || fname[ i ] == '\\'
#endif
          )
        {
            end = i - 1;
            break;
        }
    }

    if( end < 0 )
        return out;

    for( i = 0; i < end && i < max_len; i++ )
        out[ i ] = fname[ i ];

    out[ i ] = 0;

    return out;
}


//-----------------------------------------------------------------------//
void file_copy( const char *src, const char *dst )
{
    FILE *fs, *fd;

    fs = fopen( src, "rb" );
    if( fs == NULL )
        THROW( e_file_read, "Can't read file from [%s]!", src );

    fd = fopen( dst, "wb" );
    if( fs == NULL )
    {
        fclose( fs );
        THROW( e_file_write, "Can't write file to [%s]!", dst );
    }

#define FCP_BUFFER_SIZE 0x10000

    ulong  fsize; // @fixme May be error, when file size > 2^32!

    fseek( fs, 0, 2 );
    fsize = ftell( fs );
    fseek( fs, 0, 0 );

    if( fsize == 0 )
    {
        fclose( fs );
        fclose( fd );
        return;
    }

    char  *buffer;

    ulong  buffer_cnt = fsize / FCP_BUFFER_SIZE,
           buffer_mod = fsize % FCP_BUFFER_SIZE;

    try
    {
        buffer = new char[ FCP_BUFFER_SIZE ];
    }
    catch( std::exception &exc )
    {
        fclose( fs );
        fclose( fd );
        THROW( e_file_read,
            "Can't allocate [%ld] bytes for buffer!", FCP_BUFFER_SIZE );
    }

    while( buffer_cnt-- )
    {
        fread ( buffer, FCP_BUFFER_SIZE, 1, fs );
        fwrite( buffer, FCP_BUFFER_SIZE, 1, fd );
    }

    fread ( buffer, buffer_mod, 1, fs );
    fwrite( buffer, buffer_mod, 1, fd );

    delete []buffer;

    fflush( fd );
    fclose( fd );
    fclose( fs );
    return;

#undef FCP_BUFFER_SIZE
//    char full_line[ 2048 ];
//#ifndef _WIN32
//    sprintf( full_line, "cp -f %s %s", src, dst );
//#else
//    sprintf( full_line, "copy /Q %s %s", src, dst );
//#endif

//    system( full_line );


}


//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
// @brief The main exception class.
cexception::cexception( )
{
    file         =   exception_label =
                     function        = (char*)"";

    line         = 0;
    message[ 0 ] = 0;
}

//-----------------------------------------------------------------------//
cexception::cexception( const char *fl,
            const char *exc_lbl,
            const char *func,
            const int   l )
{
    this->exception_label = (char*)exc_lbl;
    this->function        = (char*)func;
    this->file            = (char*)fl;
    this->line            = l;
}

//-----------------------------------------------------------------------//
void cexception::set_message( const char *fmt, ... )
{
    va_list   args;

    va_start( args, fmt );

    ccritical_section::enter(); // ===>>
    vsnprintf( message, 256, fmt, args );
    ccritical_section::leave(); // <<===

    va_end( args );
}

//-----------------------------------------------------------------------//
const char* cexception::get_formated_message( )
{
    ccritical_section::enter(); // ===>>

    snprintf( buffer, 256,
              "<<%s>>%s(%ld)[%s]: %s",
               this->exception_label,
               this->file,
               this->line,
               this->function,
               this->message );

    ccritical_section::leave(); // <<===

    return buffer;
}

//-----------------------------------------------------------------------//
const char* cexception::get_message() const
{
    return this->message;
}

//-----------------------------------------------------------------------//
const char* cexception::get_file() const
{
    return this->file;
}

//-----------------------------------------------------------------------//
const char* cexception::get_exception_name() const
{
    return this->exception_label;
}

//-----------------------------------------------------------------------//
const int   cexception::get_line() const
{
    return this->line;
}

//-----------------------------------------------------------------------//
const char* cexception::get_function() const
{
    return this->function;
}
